Prerequisites

Loading the required packages

library(tidyverse)
library(dplyr)
library(ggplot2)
library(rtweet)
library(readr)
library(DataExplorer)

Dataset

Import processed data, which can be found here.

#read preprocessed data
wines <- read.csv(file = '../data/processed_data/wines.csv')

Get sample of dataset

#set seed value to birthday of Ricardo Rodriguez, American wrestler and ring announcer and Dr. Reinaldo (Rei) Sanchez-Arias
set.seed(19630217)

#set percentage to test with for simplicity, if needed
percentage <- 5
wine_sample<- sample_n(wines, percentage/100*nrow(wines))

Split Taster data into different Data Frame

tasters <- wines %>%
  select(taster_name, taster_twitter_handle) %>% unique()
tasters
<<<<<<< HEAD
======= >>>>>>> 5eefb62a423836334020d43ec36a96579d6cc365

Drop taster_twitter_handle in wines dataframe

wines <- wines %>%
  select(-taster_twitter_handle)
head(wines)
<<<<<<< HEAD
======= >>>>>>> 5eefb62a423836334020d43ec36a96579d6cc365

Add Reviewer profile info

Each reviewer has there own bias. To offset that we made a “profile” for each reviewer which includes characteristics like: avg_points, sd_points, and var_points

taster_rating_profile <- wines %>%
  group_by(taster_name) %>%
  summarize(
    avg_points = mean(points),
    sd_points = sd(points),
    var_points = var(points),
    reviews = n()
  )

tasters <- inner_join(tasters, taster_rating_profile, by = "taster_name")
head(tasters)

Add Rating Classification

Add following classification to wine dataset as found on the website:

Category Rating Description
Classic 98-100 The pinnacle of quality.
Superb 94-97 A great achievement.
Excellent 90-93 Highly recommended.
Very Good 87-89 Often good value; well recommended.
Good 83-86 Suitable for everyday consumption; often good value.
Acceptable 80-82 Can be employed in casual, less-critical circumstances
# function to add rating
rating_category <- function(points){
  if(points>=98){
    return("Classic")
  }
  else if (points>=94){
    return("Superb")
  }
  else if(points>=90){
    return("Excellent")
  }
  else if(points>=87){
    return("Very Good")
  }
  else if(points>=83){
    return("Good")
  }
  else{
    return("Acceptable")
  }
}

wines<- wines %>%
  rowwise() %>%
  mutate(rating_category = rating_category(points))
head(wines)

Add Adjusted Points

Since, each reviewer has a different bias we created a normalized metric, norm_points, by looking at the number of standard deviatioins a wine is from the reviewer’s avg_points. This gives use a more accurate representation of which which wines are better than the rest.

normalize_points <- function(data){
  left_join(data, tasters, by = "taster_name")%>%
    rowwise() %>%
    mutate(norm_points = (points-avg_points)/sd_points) %>%
    select(-avg_points, -sd_points, -var_points, -taster_twitter_handle, -reviews)
}

wines <- normalize_points(wines)
head(wines) 

Data Sanitation

Vintage seems to have year 7200

wines <- wines %>%
  filter(vintage<2019)

Data Exploration

Univariate Exploration

Correlating price by points, using DataExplorer library which can be found here

plot_correlation(c('wines$price', 'wines$points'))

Alcohol Amount

wines %>% 
  group_by(alcohol) %>% 
  ggplot(mapping = aes(x = alcohol)) +
  geom_histogram(na.rm = T,
                 bins = 50) +
  scale_x_continuous(name = "Alchohol Percentage", breaks = seq(0,25,1), limits = c(0,25))

Category

wines %>% 
#  group_by(points) %>% 
#  count(category) %>%  
  ggplot() +
  facet_wrap(~ category) +
  geom_point(mapping = aes(x=points, y = price))

Vintage

Count wines per year (Note: Data has been sanitized)

wines %>%
  group_by(vintage) %>%
  summarize(count = n())
Grouping rowwise data frame strips rowwise nature
wines %>%
  ggplot() +
  geom_bar(mapping = aes(x=vintage))

Winery

To better understand the number wines per winery, we did a univarite visualization that counts the number of wines per winery showing only 15 winerys to give you an idea what winery has the most selction of wines.

<<<<<<< HEAD
wines %>%
  group_by(winery) %>%==
Error: unexpected '==' in:
"wines %>%
  group_by(winery) %>%=="
=======
wines %>%
  group_by(winery) %>%==
  summarize(count = n()) %>%
  arrange(desc(count)) %>%
  slice(1:15) %>%
  ggplot() +
  geom_col(mapping = aes(x=count, y =winery)) 
>>>>>>> 5eefb62a423836334020d43ec36a96579d6cc365

Province

To better understand the number wines per province, we did a univarite visualization that counts the number of wines per province showing only the top 10 provinces with the most wines. This can give the reader an idea where their wine will most likely be made with California standing out as a clear leader.

wines %>% 
  group_by(province) %>% 
  summarize(count = n()) %>% 
  arrange(desc(count)) %>% 
  slice(1:10) %>% 
  ggplot()+
  geom_col(aes(x = count, y = province))

Price

Calculating the Mean, Standard Deviation, Minimum, and Max Price for the entire wine dataset and printing the values.

mean_price <- print(mean(wines$price, na.rm = TRUE))
sd_price <- print(sd(wines$price, na.rm = TRUE))
min_price <- print(min(wines$price, na.rm = TRUE))
max_price <- print(max(wines$price, na.rm = TRUE))

Points

Calculating the Mean, Standard Deviation, Minimum, and Max Points for the entire wine dataset and printing the values.

print(mean(wines$points))
print(sd(wines$points))
print(min(wines$points))
print(max(wines$points))

To help you understand the point distribution by reviewers, we did a multivarite visualization that coorelates some taster names based on the average wine points as identified by the x-intercept. This give you the reader an idea of how some reviewers correlate to the overall average.

wines %>%
  ggplot() +
  geom_boxplot(aes(y=taster_name, x=points)) +
  geom_vline(xintercept = mean(wines$points))

Multivariate Exploration

Price by Points

Notice the data is “stacked” and the socres range from 80-100

TODO: IZZY (Why did we log this?)

Data Analysis

To help you understand the data analysis, we found the best province for wine by using the average points across the wines.

<<<<<<< HEAD
mean_points <- mean(wines$points)
best_province <- wines %>% 
  summarise(province) %>% 
=======

mean_points <- mean(wines$points)
mean_points

best_province <- wines %>% 
  group_by(points) %>% 
>>>>>>> 5eefb62a423836334020d43ec36a96579d6cc365
  filter(points > mean_points) %>% 
  arrange(desc(points)) %>%  
  ggplot() +
  geom_col(mapping = aes(x= province, y = points)) 
<<<<<<< HEAD
Error in points > mean_points : 
  comparison (6) is possible only for atomic and list types
======= >>>>>>> 5eefb62a423836334020d43ec36a96579d6cc365

Best wine, by variety

#wine_best_variety <- 
wines %>% 
  group_by(variety) %>% 
  summarise(mean_points = mean(points)) %>% 
  arrange(desc(mean_points)) 
NA
user_price <- readline(prompt = "How much are you willing to spend on a bottle?")
user_price <- as.integer(user_price)

wines %>% 
  filter(price <= user_price) %>% 
  arrange(desc(points)) %>% 
  select(title, price, points)

Conclusion

<<<<<<< HEAD
LS0tDQp0aXRsZTogIkV4cGxvcmluZyBhbmQgQW5hbHlpemluZyBXaW5lIEVudGh1c2lhc3QgUmV2aWV3cyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMgUHJlcmVxdWlzaXRlcw0KDQpMb2FkaW5nIHRoZSByZXF1aXJlZCBwYWNrYWdlcw0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHJ0d2VldCkNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KERhdGFFeHBsb3JlcikNCmBgYA0KDQojIERhdGFzZXQNCg0KSW1wb3J0IHByb2Nlc3NlZCBkYXRhLCB3aGljaCBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9DNHJieW4zbTRuL3dpbmVfcmV2aWV3c19kYXRhX2FuYWx5c2lzL2Jsb2IvbWFzdGVyL2RhdGEvcHJvY2Vzc2VkX2RhdGEvcHJlcHJvY2Vzc2luZy5ybWQpLg0KDQpgYGB7cn0NCiNyZWFkIHByZXByb2Nlc3NlZCBkYXRhDQp3aW5lcyA8LSByZWFkLmNzdihmaWxlID0gJy4uL2RhdGEvcHJvY2Vzc2VkX2RhdGEvd2luZXMuY3N2JykNCmBgYA0KDQpHZXQgc2FtcGxlIG9mIGRhdGFzZXQNCmBgYHtyfQ0KI3NldCBzZWVkIHZhbHVlIHRvIGJpcnRoZGF5IG9mIFJpY2FyZG8gUm9kcmlndWV6LCBBbWVyaWNhbiB3cmVzdGxlciBhbmQgcmluZyBhbm5vdW5jZXIgYW5kIERyLiBSZWluYWxkbyAoUmVpKSBTYW5jaGV6LUFyaWFzDQpzZXQuc2VlZCgxOTYzMDIxNykNCg0KI3NldCBwZXJjZW50YWdlIHRvIHRlc3Qgd2l0aCBmb3Igc2ltcGxpY2l0eSwgaWYgbmVlZGVkDQpwZXJjZW50YWdlIDwtIDUNCndpbmVfc2FtcGxlPC0gc2FtcGxlX24od2luZXMsIHBlcmNlbnRhZ2UvMTAwKm5yb3cod2luZXMpKQ0KYGBgDQoNCiMjIyBTcGxpdCBUYXN0ZXIgZGF0YSBpbnRvIGRpZmZlcmVudCBEYXRhIEZyYW1lDQoNCmBgYHtyfQ0KdGFzdGVycyA8LSB3aW5lcyAlPiUNCiAgc2VsZWN0KHRhc3Rlcl9uYW1lLCB0YXN0ZXJfdHdpdHRlcl9oYW5kbGUpICU+JSB1bmlxdWUoKQ0KdGFzdGVycw0KYGBgDQoNCkRyb3AgYHRhc3Rlcl90d2l0dGVyX2hhbmRsZWAgaW4gd2luZXMgZGF0YWZyYW1lDQoNCmBgYHtyfQ0Kd2luZXMgPC0gd2luZXMgJT4lDQogIHNlbGVjdCgtdGFzdGVyX3R3aXR0ZXJfaGFuZGxlKQ0KaGVhZCh3aW5lcykNCmBgYA0KIyMgQWRkIFJldmlld2VyIHByb2ZpbGUgaW5mbw0KDQpFYWNoIHJldmlld2VyIGhhcyB0aGVyZSBvd24gYmlhcy4gVG8gb2Zmc2V0IHRoYXQgd2UgbWFkZSBhICJwcm9maWxlIiBmb3IgZWFjaCByZXZpZXdlciB3aGljaCBpbmNsdWRlcyBjaGFyYWN0ZXJpc3RpY3MgbGlrZTogYGF2Z19wb2ludHNgLCBgc2RfcG9pbnRzYCwgYW5kIGB2YXJfcG9pbnRzYA0KYGBge3J9DQp0YXN0ZXJfcmF0aW5nX3Byb2ZpbGUgPC0gd2luZXMgJT4lDQogIGdyb3VwX2J5KHRhc3Rlcl9uYW1lKSAlPiUNCiAgc3VtbWFyaXplKA0KICAgIGF2Z19wb2ludHMgPSBtZWFuKHBvaW50cyksDQogICAgc2RfcG9pbnRzID0gc2QocG9pbnRzKSwNCiAgICB2YXJfcG9pbnRzID0gdmFyKHBvaW50cyksDQogICAgcmV2aWV3cyA9IG4oKQ0KICApDQoNCnRhc3RlcnMgPC0gaW5uZXJfam9pbih0YXN0ZXJzLCB0YXN0ZXJfcmF0aW5nX3Byb2ZpbGUsIGJ5ID0gInRhc3Rlcl9uYW1lIikNCmhlYWQodGFzdGVycykNCmBgYA0KIyMjIEFkZCBSYXRpbmcgQ2xhc3NpZmljYXRpb24NCg0KQWRkIGZvbGxvd2luZyBjbGFzc2lmaWNhdGlvbiB0byB3aW5lIGRhdGFzZXQgYXMgZm91bmQgb24gdGhlIFt3ZWJzaXRlXShodHRwczovL3d3dy53aW5lbWFnLmNvbS8yMDEwLzA0LzA5L3lvdS1hc2tlZC1ob3ctaXMtYS13aW5lcy1zY29yZS1kZXRlcm1pbmVkLyk6DQoNCnxDYXRlZ29yeSAgfCBSYXRpbmcgIHwgRGVzY3JpcHRpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwtLS0tLS0tLS0tfC0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwNCnxDbGFzc2ljICAgfAk5OC0xMDAgfCBUaGUgcGlubmFjbGUgb2YgcXVhbGl0eS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfFN1cGVyYiAgICB8CTk0LTk3CSB8IEEgZ3JlYXQgYWNoaWV2ZW1lbnQuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8RXhjZWxsZW50IHwJOTAtOTMJIHwgSGlnaGx5IHJlY29tbWVuZGVkLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnxWZXJ5IEdvb2QgfCAgODctODkJIHwgT2Z0ZW4gZ29vZCB2YWx1ZTsgd2VsbCByZWNvbW1lbmRlZC4gICAgICAgICAgICAgICAgICAgIHwNCnxHb29kCSAgICAgfCAgODMtODYJIHwgU3VpdGFibGUgZm9yIGV2ZXJ5ZGF5IGNvbnN1bXB0aW9uOyBvZnRlbiBnb29kIHZhbHVlLiAgIHwNCnxBY2NlcHRhYmxlfAk4MC04MgkgfCBDYW4gYmUgZW1wbG95ZWQgaW4gY2FzdWFsLCBsZXNzLWNyaXRpY2FsIGNpcmN1bXN0YW5jZXMgfA0KDQpgYGB7cn0NCiMgZnVuY3Rpb24gdG8gYWRkIHJhdGluZw0KcmF0aW5nX2NhdGVnb3J5IDwtIGZ1bmN0aW9uKHBvaW50cyl7DQogIGlmKHBvaW50cz49OTgpew0KICAgIHJldHVybigiQ2xhc3NpYyIpDQogIH0NCiAgZWxzZSBpZiAocG9pbnRzPj05NCl7DQogICAgcmV0dXJuKCJTdXBlcmIiKQ0KICB9DQogIGVsc2UgaWYocG9pbnRzPj05MCl7DQogICAgcmV0dXJuKCJFeGNlbGxlbnQiKQ0KICB9DQogIGVsc2UgaWYocG9pbnRzPj04Nyl7DQogICAgcmV0dXJuKCJWZXJ5IEdvb2QiKQ0KICB9DQogIGVsc2UgaWYocG9pbnRzPj04Myl7DQogICAgcmV0dXJuKCJHb29kIikNCiAgfQ0KICBlbHNlew0KICAgIHJldHVybigiQWNjZXB0YWJsZSIpDQogIH0NCn0NCg0Kd2luZXM8LSB3aW5lcyAlPiUNCiAgcm93d2lzZSgpICU+JQ0KICBtdXRhdGUocmF0aW5nX2NhdGVnb3J5ID0gcmF0aW5nX2NhdGVnb3J5KHBvaW50cykpDQpoZWFkKHdpbmVzKQ0KYGBgDQoNCiMjIEFkZCBBZGp1c3RlZCBQb2ludHMNCg0KU2luY2UsIGVhY2ggcmV2aWV3ZXIgaGFzIGEgZGlmZmVyZW50IGJpYXMgd2UgY3JlYXRlZCBhIG5vcm1hbGl6ZWQgbWV0cmljLCBgbm9ybV9wb2ludHNgLCBieSBsb29raW5nIGF0IHRoZSBudW1iZXIgb2Ygc3RhbmRhcmQgZGV2aWF0aW9pbnMgYSB3aW5lIGlzIGZyb20gdGhlIHJldmlld2VyJ3MgYGF2Z19wb2ludHNgLiBUaGlzIGdpdmVzIHVzZSBhIG1vcmUgYWNjdXJhdGUgcmVwcmVzZW50YXRpb24gb2Ygd2hpY2ggd2hpY2ggd2luZXMgYXJlIGJldHRlciB0aGFuIHRoZSByZXN0Lg0KDQpgYGB7cn0NCm5vcm1hbGl6ZV9wb2ludHMgPC0gZnVuY3Rpb24oZGF0YSl7DQogIGxlZnRfam9pbihkYXRhLCB0YXN0ZXJzLCBieSA9ICJ0YXN0ZXJfbmFtZSIpJT4lDQogICAgcm93d2lzZSgpICU+JQ0KICAgIG11dGF0ZShub3JtX3BvaW50cyA9IChwb2ludHMtYXZnX3BvaW50cykvc2RfcG9pbnRzKSAlPiUNCiAgICBzZWxlY3QoLWF2Z19wb2ludHMsIC1zZF9wb2ludHMsIC12YXJfcG9pbnRzLCAtdGFzdGVyX3R3aXR0ZXJfaGFuZGxlLCAtcmV2aWV3cykNCn0NCg0Kd2luZXMgPC0gbm9ybWFsaXplX3BvaW50cyh3aW5lcykNCmhlYWQod2luZXMpIA0KYGBgDQoNCiMjIERhdGEgU2FuaXRhdGlvbg0KDQpWaW50YWdlIHNlZW1zIHRvIGhhdmUgeWVhciA3MjAwDQpgYGAge3J9DQp3aW5lcyA8LSB3aW5lcyAlPiUNCiAgZmlsdGVyKHZpbnRhZ2U8MjAxOSkNCmBgYA0KIyBEYXRhIEV4cGxvcmF0aW9uDQoNCiMjIFVuaXZhcmlhdGUgRXhwbG9yYXRpb24NCkNvcnJlbGF0aW5nIGBwcmljZWAgYnkgYHBvaW50c2AsIHVzaW5nIGBgYERhdGFFeHBsb3JlcmBgYCBsaWJyYXJ5IHdoaWNoIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9kYXRhc2NpZW5jZXBsdXMuY29tL2JsYXppbmctZmFzdC1lZGEtaW4tci13aXRoLWRhdGFleHBsb3Jlci8pDQpgYGB7cn0NCiMgVE9ETzogSVpaWQ0KYGBgDQoNCiMjIyBBbGNvaG9sIEFtb3VudA0KYGBge3J9DQojIFRPRE86IElaWlkNCmBgYA0KDQojIyMgQ2F0ZWdvcnkNCmBgYHtyfQ0KIyBUT0RPOiBJWlpZDQpgYGANCg0KIyMjIFZpbnRhZ2UNCkNvdW50IHdpbmVzIHBlciB5ZWFyIChOb3RlOiBEYXRhIGhhcyBiZWVuIHNhbml0aXplZCkNCmBgYHtyfQ0Kd2luZXMgJT4lDQogIGdyb3VwX2J5KHZpbnRhZ2UpICU+JQ0KICBzdW1tYXJpemUoY291bnQgPSBuKCkpDQpgYGANCg0KDQpgYGB7cn0NCndpbmVzICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeD12aW50YWdlKSkNCmBgYA0KDQojIyMgV2luZXJ5DQpUbyBiZXR0ZXIgdW5kZXJzdGFuZCB0aGUgbnVtYmVyIHdpbmVzIHBlciB3aW5lcnksIHdlIGRpZCBhIHVuaXZhcml0ZSB2aXN1YWxpemF0aW9uIHRoYXQgY291bnRzIHRoZSBudW1iZXIgb2Ygd2luZXMgcGVyIHdpbmVyeSBzaG93aW5nIG9ubHkgMTUgd2luZXJ5cyB0byBnaXZlIHlvdSBhbiBpZGVhIHdoYXQgd2luZXJ5IGhhcyB0aGUgbW9zdCBzZWxjdGlvbiBvZiB3aW5lcy4NCmBgYHtyfQ0Kd2luZXMgJT4lDQogIGdyb3VwX2J5KHdpbmVyeSkgJT4lPT0NCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKSAlPiUNCiAgYXJyYW5nZShkZXNjKGNvdW50KSkgJT4lDQogIHNsaWNlKDE6MTUpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fY29sKG1hcHBpbmcgPSBhZXMoeD1jb3VudCwgeSA9d2luZXJ5KSkgDQpgYGANCg0KIyMjIFByb3ZpbmNlDQpUbyBiZXR0ZXIgdW5kZXJzdGFuZCB0aGUgbnVtYmVyIHdpbmVzIHBlciBwcm92aW5jZSwgd2UgZGlkIGEgdW5pdmFyaXRlIHZpc3VhbGl6YXRpb24gdGhhdCBjb3VudHMgdGhlIG51bWJlciBvZiB3aW5lcyBwZXIgcHJvdmluY2Ugc2hvd2luZyBvbmx5IHRoZSB0b3AgMTAgcHJvdmluY2VzIHdpdGggdGhlIG1vc3Qgd2luZXMuIFRoaXMgY2FuIGdpdmUgdGhlIHJlYWRlciBhbiBpZGVhIHdoZXJlIHRoZWlyIHdpbmUgd2lsbCBtb3N0IGxpa2VseSBiZSBtYWRlIHdpdGggQ2FsaWZvcm5pYSBzdGFuZGluZyBvdXQgYXMgYSBjbGVhciBsZWFkZXIuDQpgYGB7cn0NCndpbmVzICU+JSANCiAgZ3JvdXBfYnkocHJvdmluY2UpICU+JSANCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhjb3VudCkpICU+JSANCiAgc2xpY2UoMToxMCkgJT4lIA0KICBnZ3Bsb3QoKSsNCiAgZ2VvbV9jb2woYWVzKHggPSBjb3VudCwgeSA9IHByb3ZpbmNlKSkNCmBgYA0KDQojIyMgUHJpY2UNCkNhbGN1bGF0aW5nIHRoZSBNZWFuLCBTdGFuZGFyZCBEZXZpYXRpb24sIE1pbmltdW0sIGFuZCBNYXggUHJpY2UgZm9yIHRoZSBlbnRpcmUgd2luZSBkYXRhc2V0IGFuZCBwcmludGluZyB0aGUgdmFsdWVzLg0KYGBge3J9DQptZWFuX3ByaWNlIDwtIHByaW50KG1lYW4od2luZXMkcHJpY2UsIG5hLnJtID0gVFJVRSkpDQpzZF9wcmljZSA8LSBwcmludChzZCh3aW5lcyRwcmljZSwgbmEucm0gPSBUUlVFKSkNCm1pbl9wcmljZSA8LSBwcmludChtaW4od2luZXMkcHJpY2UsIG5hLnJtID0gVFJVRSkpDQptYXhfcHJpY2UgPC0gcHJpbnQobWF4KHdpbmVzJHByaWNlLCBuYS5ybSA9IFRSVUUpKQ0KYGBgDQoNCiMjIyAgUG9pbnRzIA0KQ2FsY3VsYXRpbmcgdGhlIE1lYW4sIFN0YW5kYXJkIERldmlhdGlvbiwgTWluaW11bSwgYW5kIE1heCBQb2ludHMgZm9yIHRoZSBlbnRpcmUgd2luZSBkYXRhc2V0IGFuZCBwcmludGluZyB0aGUgdmFsdWVzLg0KYGBge3J9DQpwcmludChtZWFuKHdpbmVzJHBvaW50cykpDQpwcmludChzZCh3aW5lcyRwb2ludHMpKQ0KcHJpbnQobWluKHdpbmVzJHBvaW50cykpDQpwcmludChtYXgod2luZXMkcG9pbnRzKSkNCg0KYGBgDQoNCg0KDQpUbyBoZWxwIHlvdSB1bmRlcnN0YW5kIHRoZSBwb2ludCBkaXN0cmlidXRpb24gYnkgcmV2aWV3ZXJzLCB3ZSBkaWQgYSBtdWx0aXZhcml0ZSB2aXN1YWxpemF0aW9uIHRoYXQgY29vcmVsYXRlcyBzb21lIHRhc3RlciBuYW1lcyBiYXNlZCBvbiB0aGUgYXZlcmFnZSB3aW5lIHBvaW50cyBhcyBpZGVudGlmaWVkICBieSB0aGUgeC1pbnRlcmNlcHQuIFRoaXMgZ2l2ZSB5b3UgdGhlIHJlYWRlciBhbiBpZGVhIG9mIGhvdyBzb21lIHJldmlld2VycyBjb3JyZWxhdGUgdG8gdGhlIG92ZXJhbGwgYXZlcmFnZS4NCmBgYHtyfQ0Kd2luZXMgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9ib3hwbG90KGFlcyh5PXRhc3Rlcl9uYW1lLCB4PXBvaW50cykpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVhbih3aW5lcyRwb2ludHMpKQ0KYGBgDQoNCiMjIE11bHRpdmFyaWF0ZSBFeHBsb3JhdGlvbg0KDQojIyBQcmljZSBieSBQb2ludHMNCk5vdGljZSB0aGUgZGF0YSBpcyAic3RhY2tlZCIgYW5kIHRoZSBzb2NyZXMgcmFuZ2UgZnJvbSA4MC0xMDANCmBgYHtyfQ0Kd2luZXMgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IChhZXMoeCA9IHBvaW50cywgeSA9IHByaWNlKSksIG5hLnJtID0gVCwgYWxwaGEgPSAwLjE1KSArDQogIGxhYnModGl0bGUgPSAiUHJpY2UgYnkgUG9pbnRzIiwgeCA9ICJQb2ludHMiLCB5ID0gIlByaWNlIikNCmBgYA0KDQpUT0RPOiBJWlpZIChXaHkgZGlkIHdlIGxvZyB0aGlzPykNCg0KYGBge3J9DQp3aW5lcyAlPiUgDQogIGdncGxvdCgpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gKGFlcyh4ID0gcG9pbnRzLCB5ID0gbG9nKHByaWNlKSkpLCBuYS5ybSA9IFQsIGFscGhhID0gMC4xNSkgKw0KICBsYWJzKHRpdGxlID0gImxvZyhQcmljZSkgYnkgUG9pbnRzIiwgeCA9ICJQb2ludHMiLCB5ID0gImxvZyhQcmljZSkiKQ0KYGBgDQoNCiMgRGF0YSBBbmFseXNpcw0KVG8gaGVscCB5b3UgdW5kZXJzdGFuZCB0aGUgZGF0YSBhbmFseXNpcywgd2UgZm91bmQgdGhlIGJlc3QgcHJvdmluY2UgZm9yIHdpbmUgYnkgdXNpbmcgdGhlIGF2ZXJhZ2UgcG9pbnRzIGFjcm9zcyB0aGUgd2luZXMuIA0KYGBge3J9DQptZWFuX3BvaW50cyA8LSBtZWFuKHdpbmVzJHBvaW50cykNCmJlc3RfcHJvdmluY2UgPC0gd2luZXMgJT4lIA0KICBzdW1tYXJpc2UocHJvdmluY2UpICU+JSANCiAgZmlsdGVyKHBvaW50cyA+IG1lYW5fcG9pbnRzKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhwb2ludHMpKSAlPiUgIA0KICBnZ3Bsb3QoKSArDQogIGdlb21fY29sKG1hcHBpbmcgPSBhZXMoeD0gcHJvdmluY2UsIHkgPSBwb2ludHMpKSANCmJlc3RfcHJvdmluY2UNCmBgYA0KDQoNCkJlc3Qgd2luZSwgYnkgdmFyaWV0eQ0KYGBge3J9DQojd2luZV9iZXN0X3ZhcmlldHkgPC0gDQp3aW5lcyAlPiUgDQogIGdyb3VwX2J5KHZhcmlldHkpICU+JSANCiAgc3VtbWFyaXNlKG1lYW5fcG9pbnRzID0gbWVhbihwb2ludHMpKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhtZWFuX3BvaW50cykpIA0KICANCmBgYA0KDQpgYGB7cn0NCnVzZXJfcHJpY2UgPC0gcmVhZGxpbmUocHJvbXB0ID0gIkhvdyBtdWNoIGFyZSB5b3Ugd2lsbGluZyB0byBzcGVuZCBvbiBhIGJvdHRsZT8iKQ0KdXNlcl9wcmljZSA8LSBhcy5pbnRlZ2VyKHVzZXJfcHJpY2UpDQoNCndpbmVzICU+JSANCiAgZmlsdGVyKHByaWNlIDw9IHVzZXJfcHJpY2UpICU+JSANCiAgYXJyYW5nZShkZXNjKHBvaW50cykpICU+JSANCiAgc2VsZWN0KHRpdGxlLCBwcmljZSwgcG9pbnRzKQ0KYGBgDQoNCg0KIyBDb25jbHVzaW9uDQo=
=======
LS0tDQp0aXRsZTogIkV4cGxvcmluZyBhbmQgQW5hbHlpemluZyBXaW5lIEVudGh1c2lhc3QgUmV2aWV3cyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiMgUHJlcmVxdWlzaXRlcw0KDQpMb2FkaW5nIHRoZSByZXF1aXJlZCBwYWNrYWdlcw0KYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHJ0d2VldCkNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KERhdGFFeHBsb3JlcikNCmBgYA0KDQojIERhdGFzZXQNCg0KSW1wb3J0IHByb2Nlc3NlZCBkYXRhLCB3aGljaCBjYW4gYmUgZm91bmQgW2hlcmVdKGh0dHBzOi8vZ2l0aHViLmNvbS9DNHJieW4zbTRuL3dpbmVfcmV2aWV3c19kYXRhX2FuYWx5c2lzL2Jsb2IvbWFzdGVyL2RhdGEvcHJvY2Vzc2VkX2RhdGEvcHJlcHJvY2Vzc2luZy5ybWQpLg0KDQpgYGB7cn0NCiNyZWFkIHByZXByb2Nlc3NlZCBkYXRhDQp3aW5lcyA8LSByZWFkLmNzdihmaWxlID0gJy4uL2RhdGEvcHJvY2Vzc2VkX2RhdGEvd2luZXMuY3N2JykNCmBgYA0KDQpHZXQgc2FtcGxlIG9mIGRhdGFzZXQNCmBgYHtyfQ0KI3NldCBzZWVkIHZhbHVlIHRvIGJpcnRoZGF5IG9mIFJpY2FyZG8gUm9kcmlndWV6LCBBbWVyaWNhbiB3cmVzdGxlciBhbmQgcmluZyBhbm5vdW5jZXIgYW5kIERyLiBSZWluYWxkbyAoUmVpKSBTYW5jaGV6LUFyaWFzDQpzZXQuc2VlZCgxOTYzMDIxNykNCg0KI3NldCBwZXJjZW50YWdlIHRvIHRlc3Qgd2l0aCBmb3Igc2ltcGxpY2l0eSwgaWYgbmVlZGVkDQpwZXJjZW50YWdlIDwtIDUNCndpbmVfc2FtcGxlPC0gc2FtcGxlX24od2luZXMsIHBlcmNlbnRhZ2UvMTAwKm5yb3cod2luZXMpKQ0KYGBgDQoNCiMjIyBTcGxpdCBUYXN0ZXIgZGF0YSBpbnRvIGRpZmZlcmVudCBEYXRhIEZyYW1lDQoNCmBgYHtyfQ0KdGFzdGVycyA8LSB3aW5lcyAlPiUNCiAgc2VsZWN0KHRhc3Rlcl9uYW1lLCB0YXN0ZXJfdHdpdHRlcl9oYW5kbGUpICU+JSB1bmlxdWUoKQ0KdGFzdGVycw0KYGBgDQoNCkRyb3AgYHRhc3Rlcl90d2l0dGVyX2hhbmRsZWAgaW4gd2luZXMgZGF0YWZyYW1lDQoNCmBgYHtyfQ0Kd2luZXMgPC0gd2luZXMgJT4lDQogIHNlbGVjdCgtdGFzdGVyX3R3aXR0ZXJfaGFuZGxlKQ0KaGVhZCh3aW5lcykNCmBgYA0KIyMgQWRkIFJldmlld2VyIHByb2ZpbGUgaW5mbw0KDQpFYWNoIHJldmlld2VyIGhhcyB0aGVyZSBvd24gYmlhcy4gVG8gb2Zmc2V0IHRoYXQgd2UgbWFkZSBhICJwcm9maWxlIiBmb3IgZWFjaCByZXZpZXdlciB3aGljaCBpbmNsdWRlcyBjaGFyYWN0ZXJpc3RpY3MgbGlrZTogYGF2Z19wb2ludHNgLCBgc2RfcG9pbnRzYCwgYW5kIGB2YXJfcG9pbnRzYA0KYGBge3J9DQp0YXN0ZXJfcmF0aW5nX3Byb2ZpbGUgPC0gd2luZXMgJT4lDQogIGdyb3VwX2J5KHRhc3Rlcl9uYW1lKSAlPiUNCiAgc3VtbWFyaXplKA0KICAgIGF2Z19wb2ludHMgPSBtZWFuKHBvaW50cyksDQogICAgc2RfcG9pbnRzID0gc2QocG9pbnRzKSwNCiAgICB2YXJfcG9pbnRzID0gdmFyKHBvaW50cyksDQogICAgcmV2aWV3cyA9IG4oKQ0KICApDQoNCnRhc3RlcnMgPC0gaW5uZXJfam9pbih0YXN0ZXJzLCB0YXN0ZXJfcmF0aW5nX3Byb2ZpbGUsIGJ5ID0gInRhc3Rlcl9uYW1lIikNCmhlYWQodGFzdGVycykNCmBgYA0KIyMjIEFkZCBSYXRpbmcgQ2xhc3NpZmljYXRpb24NCg0KQWRkIGZvbGxvd2luZyBjbGFzc2lmaWNhdGlvbiB0byB3aW5lIGRhdGFzZXQgYXMgZm91bmQgb24gdGhlIFt3ZWJzaXRlXShodHRwczovL3d3dy53aW5lbWFnLmNvbS8yMDEwLzA0LzA5L3lvdS1hc2tlZC1ob3ctaXMtYS13aW5lcy1zY29yZS1kZXRlcm1pbmVkLyk6DQoNCnxDYXRlZ29yeSAgfCBSYXRpbmcgIHwgRGVzY3JpcHRpb24gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnwtLS0tLS0tLS0tfC0tLS0tLS0tLXwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwNCnxDbGFzc2ljICAgfAk5OC0xMDAgfCBUaGUgcGlubmFjbGUgb2YgcXVhbGl0eS4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfA0KfFN1cGVyYiAgICB8CTk0LTk3CSB8IEEgZ3JlYXQgYWNoaWV2ZW1lbnQuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB8DQp8RXhjZWxsZW50IHwJOTAtOTMJIHwgSGlnaGx5IHJlY29tbWVuZGVkLiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwNCnxWZXJ5IEdvb2QgfCAgODctODkJIHwgT2Z0ZW4gZ29vZCB2YWx1ZTsgd2VsbCByZWNvbW1lbmRlZC4gICAgICAgICAgICAgICAgICAgIHwNCnxHb29kCSAgICAgfCAgODMtODYJIHwgU3VpdGFibGUgZm9yIGV2ZXJ5ZGF5IGNvbnN1bXB0aW9uOyBvZnRlbiBnb29kIHZhbHVlLiAgIHwNCnxBY2NlcHRhYmxlfAk4MC04MgkgfCBDYW4gYmUgZW1wbG95ZWQgaW4gY2FzdWFsLCBsZXNzLWNyaXRpY2FsIGNpcmN1bXN0YW5jZXMgfA0KDQpgYGB7cn0NCiMgZnVuY3Rpb24gdG8gYWRkIHJhdGluZw0KcmF0aW5nX2NhdGVnb3J5IDwtIGZ1bmN0aW9uKHBvaW50cyl7DQogIGlmKHBvaW50cz49OTgpew0KICAgIHJldHVybigiQ2xhc3NpYyIpDQogIH0NCiAgZWxzZSBpZiAocG9pbnRzPj05NCl7DQogICAgcmV0dXJuKCJTdXBlcmIiKQ0KICB9DQogIGVsc2UgaWYocG9pbnRzPj05MCl7DQogICAgcmV0dXJuKCJFeGNlbGxlbnQiKQ0KICB9DQogIGVsc2UgaWYocG9pbnRzPj04Nyl7DQogICAgcmV0dXJuKCJWZXJ5IEdvb2QiKQ0KICB9DQogIGVsc2UgaWYocG9pbnRzPj04Myl7DQogICAgcmV0dXJuKCJHb29kIikNCiAgfQ0KICBlbHNlew0KICAgIHJldHVybigiQWNjZXB0YWJsZSIpDQogIH0NCn0NCg0Kd2luZXM8LSB3aW5lcyAlPiUNCiAgcm93d2lzZSgpICU+JQ0KICBtdXRhdGUocmF0aW5nX2NhdGVnb3J5ID0gcmF0aW5nX2NhdGVnb3J5KHBvaW50cykpDQpoZWFkKHdpbmVzKQ0KYGBgDQoNCiMjIEFkZCBBZGp1c3RlZCBQb2ludHMNCg0KU2luY2UsIGVhY2ggcmV2aWV3ZXIgaGFzIGEgZGlmZmVyZW50IGJpYXMgd2UgY3JlYXRlZCBhIG5vcm1hbGl6ZWQgbWV0cmljLCBgbm9ybV9wb2ludHNgLCBieSBsb29raW5nIGF0IHRoZSBudW1iZXIgb2Ygc3RhbmRhcmQgZGV2aWF0aW9pbnMgYSB3aW5lIGlzIGZyb20gdGhlIHJldmlld2VyJ3MgYGF2Z19wb2ludHNgLiBUaGlzIGdpdmVzIHVzZSBhIG1vcmUgYWNjdXJhdGUgcmVwcmVzZW50YXRpb24gb2Ygd2hpY2ggd2hpY2ggd2luZXMgYXJlIGJldHRlciB0aGFuIHRoZSByZXN0Lg0KDQpgYGB7cn0NCm5vcm1hbGl6ZV9wb2ludHMgPC0gZnVuY3Rpb24oZGF0YSl7DQogIGxlZnRfam9pbihkYXRhLCB0YXN0ZXJzLCBieSA9ICJ0YXN0ZXJfbmFtZSIpJT4lDQogICAgcm93d2lzZSgpICU+JQ0KICAgIG11dGF0ZShub3JtX3BvaW50cyA9IChwb2ludHMtYXZnX3BvaW50cykvc2RfcG9pbnRzKSAlPiUNCiAgICBzZWxlY3QoLWF2Z19wb2ludHMsIC1zZF9wb2ludHMsIC12YXJfcG9pbnRzLCAtdGFzdGVyX3R3aXR0ZXJfaGFuZGxlLCAtcmV2aWV3cykNCn0NCg0Kd2luZXMgPC0gbm9ybWFsaXplX3BvaW50cyh3aW5lcykNCmhlYWQod2luZXMpIA0KYGBgDQoNCiMjIERhdGEgU2FuaXRhdGlvbg0KDQpWaW50YWdlIHNlZW1zIHRvIGhhdmUgeWVhciA3MjAwDQpgYGAge3J9DQp3aW5lcyA8LSB3aW5lcyAlPiUNCiAgZmlsdGVyKHZpbnRhZ2U8MjAxOSkNCmBgYA0KIyBEYXRhIEV4cGxvcmF0aW9uDQoNCiMjIFVuaXZhcmlhdGUgRXhwbG9yYXRpb24NCkNvcnJlbGF0aW5nIGBwcmljZWAgYnkgYHBvaW50c2AsIHVzaW5nIGBgYERhdGFFeHBsb3JlcmBgYCBsaWJyYXJ5IHdoaWNoIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9kYXRhc2NpZW5jZXBsdXMuY29tL2JsYXppbmctZmFzdC1lZGEtaW4tci13aXRoLWRhdGFleHBsb3Jlci8pDQpgYGB7cn0NCnBsb3RfY29ycmVsYXRpb24oYygnd2luZXMkcHJpY2UnLCAnd2luZXMkcG9pbnRzJykpDQpgYGANCg0KIyMjIEFsY29ob2wgQW1vdW50DQpgYGB7cn0NCndpbmVzICU+JSANCiAgZ3JvdXBfYnkoYWxjb2hvbCkgJT4lIA0KICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gYWxjb2hvbCkpICsNCiAgZ2VvbV9oaXN0b2dyYW0obmEucm0gPSBULA0KICAgICAgICAgICAgICAgICBiaW5zID0gNTApICsNCiAgc2NhbGVfeF9jb250aW51b3VzKG5hbWUgPSAiQWxjaG9ob2wgUGVyY2VudGFnZSIsIGJyZWFrcyA9IHNlcSgwLDI1LDEpLCBsaW1pdHMgPSBjKDAsMjUpKQ0KYGBgDQoNCiMjIyBDYXRlZ29yeQ0KYGBge3J9DQp3aW5lcyAlPiUgDQojICBncm91cF9ieShwb2ludHMpICU+JSANCiMgIGNvdW50KGNhdGVnb3J5KSAlPiUgIA0KICBnZ3Bsb3QoKSArDQogIGZhY2V0X3dyYXAofiBjYXRlZ29yeSkgKw0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1wb2ludHMsIHkgPSBwcmljZSkpDQpgYGANCg0KIyMjIFZpbnRhZ2UNCkNvdW50IHdpbmVzIHBlciB5ZWFyIChOb3RlOiBEYXRhIGhhcyBiZWVuIHNhbml0aXplZCkNCmBgYHtyfQ0Kd2luZXMgJT4lDQogIGdyb3VwX2J5KHZpbnRhZ2UpICU+JQ0KICBzdW1tYXJpemUoY291bnQgPSBuKCkpDQpgYGANCg0KDQpgYGB7cn0NCndpbmVzICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fYmFyKG1hcHBpbmcgPSBhZXMoeD12aW50YWdlKSkNCmBgYA0KDQojIyMgV2luZXJ5DQpUbyBiZXR0ZXIgdW5kZXJzdGFuZCB0aGUgbnVtYmVyIHdpbmVzIHBlciB3aW5lcnksIHdlIGRpZCBhIHVuaXZhcml0ZSB2aXN1YWxpemF0aW9uIHRoYXQgY291bnRzIHRoZSBudW1iZXIgb2Ygd2luZXMgcGVyIHdpbmVyeSBzaG93aW5nIG9ubHkgMTUgd2luZXJ5cyB0byBnaXZlIHlvdSBhbiBpZGVhIHdoYXQgd2luZXJ5IGhhcyB0aGUgbW9zdCBzZWxjdGlvbiBvZiB3aW5lcy4NCmBgYHtyfQ0Kd2luZXMgJT4lDQogIGdyb3VwX2J5KHdpbmVyeSkgJT4lPT0NCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKSAlPiUNCiAgYXJyYW5nZShkZXNjKGNvdW50KSkgJT4lDQogIHNsaWNlKDE6MTUpICU+JQ0KICBnZ3Bsb3QoKSArDQogIGdlb21fY29sKG1hcHBpbmcgPSBhZXMoeD1jb3VudCwgeSA9d2luZXJ5KSkgDQpgYGANCg0KIyMjIFByb3ZpbmNlDQpUbyBiZXR0ZXIgdW5kZXJzdGFuZCB0aGUgbnVtYmVyIHdpbmVzIHBlciBwcm92aW5jZSwgd2UgZGlkIGEgdW5pdmFyaXRlIHZpc3VhbGl6YXRpb24gdGhhdCBjb3VudHMgdGhlIG51bWJlciBvZiB3aW5lcyBwZXIgcHJvdmluY2Ugc2hvd2luZyBvbmx5IHRoZSB0b3AgMTAgcHJvdmluY2VzIHdpdGggdGhlIG1vc3Qgd2luZXMuIFRoaXMgY2FuIGdpdmUgdGhlIHJlYWRlciBhbiBpZGVhIHdoZXJlIHRoZWlyIHdpbmUgd2lsbCBtb3N0IGxpa2VseSBiZSBtYWRlIHdpdGggQ2FsaWZvcm5pYSBzdGFuZGluZyBvdXQgYXMgYSBjbGVhciBsZWFkZXIuDQpgYGB7cn0NCndpbmVzICU+JSANCiAgZ3JvdXBfYnkocHJvdmluY2UpICU+JSANCiAgc3VtbWFyaXplKGNvdW50ID0gbigpKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhjb3VudCkpICU+JSANCiAgc2xpY2UoMToxMCkgJT4lIA0KICBnZ3Bsb3QoKSsNCiAgZ2VvbV9jb2woYWVzKHggPSBjb3VudCwgeSA9IHByb3ZpbmNlKSkNCmBgYA0KDQojIyMgUHJpY2UNCkNhbGN1bGF0aW5nIHRoZSBNZWFuLCBTdGFuZGFyZCBEZXZpYXRpb24sIE1pbmltdW0sIGFuZCBNYXggUHJpY2UgZm9yIHRoZSBlbnRpcmUgd2luZSBkYXRhc2V0IGFuZCBwcmludGluZyB0aGUgdmFsdWVzLg0KYGBge3J9DQptZWFuX3ByaWNlIDwtIHByaW50KG1lYW4od2luZXMkcHJpY2UsIG5hLnJtID0gVFJVRSkpDQpzZF9wcmljZSA8LSBwcmludChzZCh3aW5lcyRwcmljZSwgbmEucm0gPSBUUlVFKSkNCm1pbl9wcmljZSA8LSBwcmludChtaW4od2luZXMkcHJpY2UsIG5hLnJtID0gVFJVRSkpDQptYXhfcHJpY2UgPC0gcHJpbnQobWF4KHdpbmVzJHByaWNlLCBuYS5ybSA9IFRSVUUpKQ0KYGBgDQoNCiMjIyAgUG9pbnRzIA0KQ2FsY3VsYXRpbmcgdGhlIE1lYW4sIFN0YW5kYXJkIERldmlhdGlvbiwgTWluaW11bSwgYW5kIE1heCBQb2ludHMgZm9yIHRoZSBlbnRpcmUgd2luZSBkYXRhc2V0IGFuZCBwcmludGluZyB0aGUgdmFsdWVzLg0KYGBge3J9DQpwcmludChtZWFuKHdpbmVzJHBvaW50cykpDQpwcmludChzZCh3aW5lcyRwb2ludHMpKQ0KcHJpbnQobWluKHdpbmVzJHBvaW50cykpDQpwcmludChtYXgod2luZXMkcG9pbnRzKSkNCg0KYGBgDQoNCg0KDQpUbyBoZWxwIHlvdSB1bmRlcnN0YW5kIHRoZSBwb2ludCBkaXN0cmlidXRpb24gYnkgcmV2aWV3ZXJzLCB3ZSBkaWQgYSBtdWx0aXZhcml0ZSB2aXN1YWxpemF0aW9uIHRoYXQgY29vcmVsYXRlcyBzb21lIHRhc3RlciBuYW1lcyBiYXNlZCBvbiB0aGUgYXZlcmFnZSB3aW5lIHBvaW50cyBhcyBpZGVudGlmaWVkICBieSB0aGUgeC1pbnRlcmNlcHQuIFRoaXMgZ2l2ZSB5b3UgdGhlIHJlYWRlciBhbiBpZGVhIG9mIGhvdyBzb21lIHJldmlld2VycyBjb3JyZWxhdGUgdG8gdGhlIG92ZXJhbGwgYXZlcmFnZS4NCmBgYHtyfQ0Kd2luZXMgJT4lDQogIGdncGxvdCgpICsNCiAgZ2VvbV9ib3hwbG90KGFlcyh5PXRhc3Rlcl9uYW1lLCB4PXBvaW50cykpICsNCiAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gbWVhbih3aW5lcyRwb2ludHMpKQ0KYGBgDQoNCiMjIE11bHRpdmFyaWF0ZSBFeHBsb3JhdGlvbg0KDQojIyBQcmljZSBieSBQb2ludHMNCk5vdGljZSB0aGUgZGF0YSBpcyAic3RhY2tlZCIgYW5kIHRoZSBzb2NyZXMgcmFuZ2UgZnJvbSA4MC0xMDANCmBgYHtyfQ0Kd2luZXMgJT4lIA0KICBnZ3Bsb3QoKSArDQogIGdlb21fcG9pbnQobWFwcGluZyA9IChhZXMoeCA9IHBvaW50cywgeSA9IHByaWNlKSksIG5hLnJtID0gVCwgYWxwaGEgPSAwLjE1KSArDQogIGxhYnModGl0bGUgPSAiUHJpY2UgYnkgUG9pbnRzIiwgeCA9ICJQb2ludHMiLCB5ID0gIlByaWNlIikNCmBgYA0KDQpUT0RPOiBJWlpZIChXaHkgZGlkIHdlIGxvZyB0aGlzPykNCg0KYGBge3J9DQp3aW5lcyAlPiUgDQogIGdncGxvdCgpICsNCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gKGFlcyh4ID0gcG9pbnRzLCB5ID0gbG9nKHByaWNlKSkpLCBuYS5ybSA9IFQsIGFscGhhID0gMC4xNSkgKw0KICBsYWJzKHRpdGxlID0gImxvZyhQcmljZSkgYnkgUG9pbnRzIiwgeCA9ICJQb2ludHMiLCB5ID0gImxvZyhQcmljZSkiKQ0KYGBgDQoNCiMgRGF0YSBBbmFseXNpcw0KDQojRmluZCB0aGUgYmVzdCBwcm92aW5jZSBmb3Igd2luZSB1c2luZyB0aGUgYXZlcmFnZSBwb2ludHMgYWNyb3NzIHRoZSBkYXRhc2V0DQojZHJvcCB0aGUgZGVzY3JpcHRpb25zIG9yIGp1c3Qgc2VsZWN0IHByaWNlPyBzZXQgcG9pbnRzIHRvIG1heChwb2ludHMpDQpgYGB7cn0NCm1lYW5fcG9pbnRzIDwtIG1lYW4od2luZXMkcG9pbnRzKQ0KbWVhbl9wb2ludHMNCg0KYmVzdF9wcm92aW5jZSA8LSB3aW5lcyAlPiUgDQogIGdyb3VwX2J5KHBvaW50cykgJT4lIA0KICBmaWx0ZXIocG9pbnRzID4gbWVhbl9wb2ludHMpICU+JSANCiAgYXJyYW5nZShkZXNjKHBvaW50cykpDQpiZXN0X3Byb3ZpbmNlDQpgYGANCg0KDQpCZXN0IHdpbmUsIGJ5IHZhcmlldHkNCmBgYHtyfQ0KI3dpbmVfYmVzdF92YXJpZXR5IDwtIA0Kd2luZXMgJT4lIA0KICBncm91cF9ieSh2YXJpZXR5KSAlPiUgDQogIHN1bW1hcmlzZShtZWFuX3BvaW50cyA9IG1lYW4ocG9pbnRzKSkgJT4lIA0KICBhcnJhbmdlKGRlc2MobWVhbl9wb2ludHMpKSANCiAgDQpgYGANCg0KYGBge3J9DQp1c2VyX3ByaWNlIDwtIHJlYWRsaW5lKHByb21wdCA9ICJIb3cgbXVjaCBhcmUgeW91IHdpbGxpbmcgdG8gc3BlbmQgb24gYSBib3R0bGU/IikNCnVzZXJfcHJpY2UgPC0gYXMuaW50ZWdlcih1c2VyX3ByaWNlKQ0KDQp3aW5lcyAlPiUgDQogIGZpbHRlcihwcmljZSA8PSB1c2VyX3ByaWNlKSAlPiUgDQogIGFycmFuZ2UoZGVzYyhwb2ludHMpKSAlPiUgDQogIHNlbGVjdCh0aXRsZSwgcHJpY2UsIHBvaW50cykNCmBgYA0KDQoNCiMgQ29uY2x1c2lvbg0K
>>>>>>> 5eefb62a423836334020d43ec36a96579d6cc365